﻿#region " LICENSE "
// DRILL - Dependency Resolution Interface Layer Library
// Copyright (c) 2008-2012 Wade A. Reynolds. All rights reserved.
// http://drill.codeplex.com/
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#endregion
using System.Web;
using Drill.Core.Utilities;
using Drill.LocatorPattern;

namespace Drill.Integration.Web
{
	/// <summary>
	/// Used to locate instances of HttpContextBase.
	/// </summary>
	/// <remarks>
	/// <para>
	///		This class decouples an ASP.NET application from the HttpContext class 
	///		and enables testing by injecting the proper HttpContextBase instance 
	///		into the constructor. 
	/// </para>
	/// <para>
	///		When using the default constructor, a wrapped instance of HttpContext.Current
	///		is returned as long as it is valid for the current context, otherwise 
	///		it will only return null.
	/// </para>
	/// <para>
	///		For unit testing, the test HttpContextBase instance 
	///		can be injected by a DI/IoC framework, a dependency resolver super type 
	///		or manually in code.
	/// </para>
	/// <para>
	///		ASP.NET applications should always get an instance of HttpContextBase 
	///		by using this locator and never directly use the HttpContext class 
	///		in order to fully decouple the app from HttpContext and allow testing 
	///		with mock/fake implementations of HttpContextBase.
	/// </para>
	/// </remarks>
	public class HttpContextLocator : Locator<HttpContextBase>
	{
		private readonly HttpContextBase _httpContext;

		/// <summary>
		/// Initializes a new instance of the <see cref="HttpContextLocator" /> class
		/// that will attempt to return a wrapped instance of HttpContext.Current.
		/// </summary>
		public HttpContextLocator()
		{
			_httpContext = null;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="HttpContextLocator" /> class 
		/// that returns the specified HttpContextBase instance.
		/// </summary>
		/// <param name="httpContext">The HttpContextBase insatnce to be returned.</param>
		/// <remarks>
		/// If the <paramref name="httpContext"/> parameter is null, the <see cref="HttpContextLocator"/> 
		/// will attempt to return a wrapped instance of HttpContext.Current.
		/// </remarks>
		public HttpContextLocator(HttpContextBase httpContext)
		{
			_httpContext = httpContext;
		}

		/// <summary>
		/// Locates the HttpContextBase instance.
		/// </summary>
		/// <returns>An instance of HttpContextBase or null if an instance cannot be located.</returns>
		protected override HttpContextBase LocateInstance()
		{
			CheckDisposed();
			return _httpContext ?? GetDefaultHttpContextBase();
		}

		private static HttpContextBase GetDefaultHttpContextBase()
		{
			return (null != HttpContext.Current) ? new HttpContextWrapper(HttpContext.Current) : null;
		}

		/// <summary>
		/// Disposes the managed resources.
		/// </summary>
		protected override void DisposeManagedResources()
		{
			base.DisposeManagedResources();

			if (null != _httpContext)
			{
				DisposeUtility.DisposeIfPossible(_httpContext);
			}
		}
	}
}